using System;
using Gtk;
using System.IO;
using CheckSFV ;
using System.Threading;
using System.ComponentModel;


public partial class MainWindow : Gtk.Window
{
	private BackgroundWorker checkWorker = new BackgroundWorker(); 	
	enum HashType
	{
		CRC32,
		MD5
	}
	
	HashType hashType;
	
	public MainWindow () : base(Gtk.WindowType.Toplevel)
	{
		Build ();
		BuildVerifyListView();
		
		FileFilter filter = new FileFilter();
		filter.Name = "sfv Files";
	
		filter.AddPattern("*.sfv");
		filter.AddPattern("*.SFV");
		
		
		this.fc.Filter = filter; //"sfv files|*.sfv";
		
		checkWorker.WorkerSupportsCancellation = true;
		checkWorker.WorkerReportsProgress = true;
		checkWorker.DoWork +=  checkWorkerDoWork;
		checkWorker.ProgressChanged += checkWorkerProgressChanged ;
		checkWorker.RunWorkerCompleted += checkWorkerRunWorkerCompleted ;
	}

	private void BuildVerifyListView ()
	{
		Gtk.TreeViewColumn col = this.lstFiles.AppendColumn ("FileName", new CellRendererText (),"text",0);
		col.Resizable = true ;
		col.Sizing = TreeViewColumnSizing.Fixed;
		col.FixedWidth = 250;
		col = this.lstFiles.AppendColumn ("CRC32", new CellRendererText (),"text",1);
		col.Sizing = TreeViewColumnSizing.Fixed;
		col.FixedWidth = 75;
		col.Resizable = true;
		col = this.lstFiles.AppendColumn ("Status", new CellRendererPixbuf (),"pixbuf",2);
		
		
		this.lstFiles.ShowAll();
		this.lstFiles.NodeStore = new NodeStore (typeof (MyTreeNode));
	}
	
	void checkWorkerRunWorkerCompleted  (object sender, RunWorkerCompletedEventArgs e)
	{
		Gtk.Application.Invoke(delegate {
			fc.Sensitive = true;
			//fc.State = StateType.Normal; //Marche pas ...
		});
	}

	void checkWorkerProgressChanged  (object sender, ProgressChangedEventArgs e)
	{
		SFVFile checkedFile = (SFVFile)e.UserState;
		Gtk.Application.Invoke (delegate {
			try {
				labelStatus.Text = e.ProgressPercentage.ToString() + " %";
						
				lstFiles.NodeStore.AddNode (new MyTreeNode (checkedFile.FileName, checkedFile.NewHash, (checkedFile.isOK ? new Gdk.Pixbuf (null,"CheckSFV.accept.png") : new Gdk.Pixbuf(null,"CheckSFV.cancel.png"))));
			
				this.progressbar.Fraction =  (double)(decimal.One * e.ProgressPercentage / 100);
	
			} catch (Exception ex) {
				MessageDialog msg = new MessageDialog(
					this,
				    DialogFlags.Modal,
				    MessageType.Error,
				    ButtonsType.Ok,
				    ex.Message ,
				   	"Ok",ResponseType.Ok );
				
				msg.Run();
				
				msg.Destroy();
			}
		});
	}

	void  checkWorkerDoWork (object sender, DoWorkEventArgs e)
	{
		SFVFiles files = (SFVFiles)e.Argument;
		int i = 0;
		foreach (SFVFile file in files)
		{
			SFVFile checkedFile = CheckFile (file, hashType);
					
			((BackgroundWorker)sender).ReportProgress ((int)decimal.Round(decimal.One * 100 / files.Count * ++i), checkedFile);
		}
	}

	protected void OnDeleteEvent (object sender, DeleteEventArgs a)
	{
		if (checkWorker.IsBusy)
			checkWorker.CancelAsync();
		
		Application.Quit ();
		a.RetVal = true;
	}
	
	protected virtual void Selection_Changed (object sender, System.EventArgs e)
	{
		try {
			fc.State = StateType.Insensitive;
			this.lstFiles.NodeStore.Clear();
			
			this.progressbar.Fraction = 0;
			this.labelStatus.Text = "0 %";
			
			SFVFiles SfvFiles = GetFilesList (fc.Filename);
			
			lstFiles.NodeStore = new NodeStore (typeof (MyTreeNode));
			this.progressbar.PulseStep =  (double)(decimal.One * 100 / SfvFiles.Count);
			
			checkWorker.RunWorkerAsync(SfvFiles);
			
		
		} catch (Exception ex) {
			MessageDialog msg = new MessageDialog(
				this,
			    DialogFlags.Modal,
			    MessageType.Error,
			    ButtonsType.Ok,
			    ex.Message ,
			   	"Ok",ResponseType.Ok );
			
			msg.Run();
			
			msg.Destroy();
		}
	}
	

	
	private SFVFile CheckFile (SFVFile file, HashType type)
	{
		try {
			System.Security.Cryptography.HashAlgorithm Hash = null;
			//Crc32 crc32 = new Crc32();
			if (type==HashType.CRC32)
				Hash = new Crc32();
			else if (type == MainWindow.HashType.MD5)
				Hash = new System.Security.Cryptography.MD5CryptoServiceProvider();
			
			if (Hash == null) return null;
			
			string filename = string.Empty; 
			
			filename = fc.CurrentFolder + System.IO.Path.DirectorySeparatorChar + file.FileName;
			
			using (FileStream f = File.Open(
				filename, 
			    FileMode.Open)) Hash.ComputeHash(f); 
			
			
			file.NewHash = GetHashValue(Hash, type);
			
		} catch (Exception ex) {
			throw ex;	
		}
		return file;
	}
	
	private string GetHashValue (System.Security.Cryptography.HashAlgorithm hash, HashType type)
	{
		if (type == MainWindow.HashType.CRC32)
			return string.Format ("{0:X8}", ((Crc32)hash).CrcValue) ;
		else if (type == MainWindow.HashType.MD5)
		{
			string retval = "";
			foreach (byte b in ((System.Security.Cryptography.MD5CryptoServiceProvider)hash).Hash) 
			{
				retval += string.Format ("{0:X2}", b) ;
			}
			return retval;
		}
		return string.Empty;
	}
	
	private SFVFiles GetFilesList (string fileName)
	{
		try {
		
			StreamReader f = File.OpenText(fileName);
			
			if ((new FileInfo (fileName)).Extension.ToUpper().Equals (".SFV"))
				hashType = MainWindow.HashType.CRC32;
			else if ((new FileInfo (fileName)).Extension.ToUpper().Equals (".MD5"))
				hashType = MainWindow.HashType.MD5;
			
			string line = string.Empty ;
			SFVFiles lstFiles = new SFVFiles ();
			do {
				line = f.ReadLine();
				
				if (line != null && !line.StartsWith(";"))
					if (hashType == MainWindow.HashType.CRC32)
						lstFiles.Add (new SFVFile (line.Substring (0, line.Length - 9), line.Substring (line.Length - 8, 8)));
					else if (hashType == MainWindow.HashType.MD5) //TODO : to correct for md5
						lstFiles.Add (new SFVFile (line.Substring (0, line.Length - 9), line.Substring (line.Length - 8, 8)));
					
							
			}while (line != null);
			
			f.Close();
			
			return lstFiles;
				
		} catch (Exception ex) {
			throw ex;
		}
	}
}